home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 April: Mac OS SDK / Dev.CD Apr 98 SDK1.toast / Development Kits (Disc 1) / QuickDraw 3D / Windows files / Q3WinSDK.exe / QD3DSDK / Samples / Win32Sample / Box3DSupport.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-27  |  14.9 KB  |  559 lines

  1. // Box3dSupport.c - QuickDraw 3d routines
  2. //
  3. // This file contains utility routines for QuickDraw 3d sample code.
  4. // This is a simple QuickDraw 3d application to draw a cube in the center 
  5. // of the main application window.  The routines in here handle setting up
  6. // the main display group, the view, the Macintosh 3D draw context, and the
  7. // camera and lighting. 
  8. //
  9. // This code is the basis of the introductory article in  d e v e l o p  issue 22
  10. //
  11. // Nick Thompson - January 6th 1995
  12. // ©1994-95 Apple computer Inc., All Rights Reserved
  13. // 
  14. //
  15. #include "Box3DSupport.h"
  16.  
  17. #define ErMath_Atan(x)    ((float)atan((double)(x)))
  18. #define    kEPSILON        1.19209290e-07
  19.  
  20.  
  21. static     TQ3Point3D    documentGroupCenter;
  22. static    float        documentGroupScale;
  23.  
  24.  
  25. TQ3ViewObject MyNewView(DocumentPtr theDocument)
  26. {
  27.     TQ3Status                myStatus;
  28.     TQ3ViewObject            myView;
  29.     TQ3DrawContextObject    myDrawContext;
  30.     TQ3RendererObject        myRenderer;
  31.     TQ3CameraObject            myCamera;
  32.     TQ3GroupObject            myLights;
  33.     
  34.     myView = Q3View_New();
  35.     
  36.     //    Create and set draw context.
  37.     switch( theDocument->drawcontextType ) 
  38.     {
  39.     case kQ3DrawContextTypeWin32DC:
  40.         if ((myDrawContext = NewWin32DCDrawContext(theDocument)) == NULL )
  41.             goto bail;
  42.         break;
  43.      case kQ3DrawContextTypeDDSurface:
  44.         goto bail;    /* TBD */
  45.     
  46.     default:
  47.     case kQ3DrawContextTypePixmap:
  48.         if ((myDrawContext = NewPixmapDrawContext(theDocument, theDocument->fPixelFormat )) == NULL )
  49.             goto bail;
  50.         break;
  51.     }
  52.         
  53.     if ((myStatus = Q3View_SetDrawContext(myView, myDrawContext)) == kQ3Failure )
  54.         goto bail;
  55.  
  56.     Q3Object_Dispose( myDrawContext ) ;
  57.     
  58.     //    Create and set renderer.
  59.     switch( theDocument->rendererType ) 
  60.     {
  61.     case kQ3RendererTypeWireFrame: // this uses the wire frame renderer
  62.         myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeWireFrame);
  63.         if ((myStatus = Q3View_SetRenderer(myView, myRenderer)) == kQ3Failure ) {
  64.             goto bail;
  65.         }
  66.         break;
  67.     default:
  68.     case kQ3RendererTypeInteractive: // this uses the interactive renderer
  69.         if ((myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeInteractive)) != NULL ) {
  70.             if ((myStatus = Q3View_SetRenderer(myView, myRenderer)) == kQ3Failure ) {
  71.                 goto bail;
  72.             }
  73.             // these two lines set us up to use the best possible renderer,
  74.             // including  hardware if it is installed.
  75.             Q3InteractiveRenderer_SetDoubleBufferBypass (myRenderer, kQ3True);                        
  76.             Q3InteractiveRenderer_SetPreferences(myRenderer, kQAVendor_BestChoice, 0);
  77.         }
  78.         else {
  79.             goto bail;
  80.         }
  81.         break;
  82.     }
  83.  
  84.     Q3Object_Dispose( myRenderer ) ;
  85.     
  86.     //    Create and set camera
  87.     if ( (myCamera = MyNewCamera(theDocument)) == NULL )
  88.         goto bail;
  89.         
  90.     if ((myStatus = Q3View_SetCamera(myView, myCamera)) == kQ3Failure )
  91.         goto bail;
  92.  
  93.     Q3Object_Dispose( myCamera ) ;
  94.     
  95.     //    Create and set lights
  96.     if ((myLights = MyNewLights()) == NULL )
  97.         goto bail;
  98.         
  99.     if ((myStatus = Q3View_SetLightGroup(myView, myLights)) == kQ3Failure )
  100.         goto bail;
  101.         
  102.     Q3Object_Dispose(myLights);
  103.  
  104.     return ( myView );
  105.     
  106. bail:
  107.     //    If any of the above failed, then don't return a view.
  108.     return ( NULL );
  109. }
  110.  
  111. TQ3Status MyResizeView( DocumentPtr theDocument,unsigned long width, unsigned long height )
  112. {
  113.     BOOL        result;
  114.     TQ3Status    aStatus = kQ3Success;
  115.     if( theDocument->fWidth == width &&
  116.            theDocument->fHeight == height )
  117.         return aStatus;
  118.  
  119.     theDocument->fWidth = width;
  120.     theDocument->fHeight = height;
  121.     if( kQ3DrawContextTypePixmap == theDocument->drawcontextType)
  122.     {
  123.         Q3Object_Dispose(theDocument->fView);
  124.         result = DeleteObject(theDocument->fBitmap);
  125.         theDocument->fBitmap = NULL;
  126.         result = DeleteDC(theDocument->fMemoryDC);
  127.         theDocument->fMemoryDC = NULL;
  128.         theDocument->fView = MyNewView(theDocument);
  129.     }
  130.     return aStatus;
  131. }
  132.  
  133. TQ3Status MyDeleteView( DocumentPtr theDocument )
  134. {
  135.     BOOL        result;
  136.     TQ3Status    aStatus = kQ3Success;
  137.  
  138.     if( kQ3DrawContextTypePixmap == theDocument->drawcontextType)
  139.     {
  140.         result = DeleteObject(theDocument->fBitmap);
  141.         result = DeleteDC(theDocument->fMemoryDC);
  142.     }
  143.  
  144.     Q3Object_Dispose(theDocument->fView);
  145.     return aStatus;
  146. }
  147.  
  148. //----------------------------------------------------------------------------------
  149.  
  150. TQ3CameraObject MyNewCamera(DocumentPtr theDocument)
  151. {
  152.     TQ3ViewAngleAspectCameraData    perspectiveData;
  153.  
  154.     TQ3CameraObject                camera;
  155.     
  156.     TQ3Point3D                     from     = { 0.0F, 0.0F, 7.0F };
  157.     TQ3Point3D                     to         = { 0.0F, 0.0F, 0.0F };
  158.     TQ3Vector3D                 up         = { 0.0F, 1.0F, 0.0F };
  159.  
  160.     float                         fieldOfView = 1.0F;
  161.     float                         hither         = 0.001F;
  162.     float                         yon         = 1000.0F;
  163.  
  164.     TQ3Status                    returnVal = kQ3Failure ;
  165.  
  166.     perspectiveData.cameraData.placement.cameraLocation     = from;
  167.     perspectiveData.cameraData.placement.pointOfInterest     = to;
  168.     perspectiveData.cameraData.placement.upVector             = up;
  169.  
  170.     perspectiveData.cameraData.range.hither    = hither;
  171.     perspectiveData.cameraData.range.yon     = yon;
  172.  
  173.     perspectiveData.cameraData.viewPort.origin.x = -1.0F;
  174.     perspectiveData.cameraData.viewPort.origin.y = 1.0F;
  175.     perspectiveData.cameraData.viewPort.width = 2.0F;
  176.     perspectiveData.cameraData.viewPort.height = 2.0F;
  177.                                                     
  178.     perspectiveData.fov                = fieldOfView;
  179.     perspectiveData.aspectRatioXToY    =
  180.         (float) (theDocument->fWidth) / 
  181.         (float) (theDocument->fHeight);
  182.         
  183.     camera = Q3ViewAngleAspectCamera_New(&perspectiveData);
  184.  
  185.     return camera ;
  186. }
  187.  
  188.  
  189. //----------------------------------------------------------------------------------
  190.  
  191. TQ3GroupObject MyNewLights()
  192. {
  193.     TQ3GroupPosition        myGroupPosition;
  194.     TQ3GroupObject            myLightList;
  195.     TQ3LightData            myLightData;
  196.     TQ3PointLightData        myPointLightData;
  197.     TQ3DirectionalLightData    myDirectionalLightData;
  198.     TQ3LightObject            myAmbientLight, myPointLight, myFillLight;
  199.     TQ3Point3D                pointLocation = { -10.0F, 0.0F, 10.0F };
  200.     TQ3Vector3D                fillDirection = { 10.0F, 0.0F, 10.0F };
  201.     TQ3ColorRGB                WhiteLight = { 1.0F, 1.0F, 1.0F };
  202.     
  203.     //    Set up light data for ambient light.  This light data will be used for point and fill
  204.     //    light also.
  205.  
  206.     myLightData.isOn = kQ3True;
  207.     myLightData.color = WhiteLight;
  208.     
  209.     //    Create ambient light.
  210.     myLightData.brightness = .25F;
  211.     myAmbientLight = Q3AmbientLight_New(&myLightData);
  212.     if ( myAmbientLight == NULL )
  213.         goto bail;
  214.     
  215.     //    Create point light.
  216.     myLightData.brightness = 1.0F;
  217.     myPointLightData.lightData = myLightData;
  218.     myPointLightData.castsShadows = kQ3False;
  219.     myPointLightData.attenuation = kQ3AttenuationTypeNone;
  220.     myPointLightData.location = pointLocation;
  221.     myPointLight = Q3PointLight_New(&myPointLightData);
  222.     if ( myPointLight == NULL )
  223.         goto bail;
  224.  
  225.     //    Create fill light.
  226.     myLightData.brightness = .3F;
  227.     myDirectionalLightData.lightData = myLightData;
  228.     myDirectionalLightData.castsShadows = kQ3False;
  229.     myDirectionalLightData.direction = fillDirection;
  230.     myFillLight = Q3DirectionalLight_New(&myDirectionalLightData);
  231.     if ( myFillLight == NULL )
  232.         goto bail;
  233.  
  234.     //    Create light group and add each of the lights into the group.
  235.     myLightList = Q3LightGroup_New();
  236.     if ( myLightList == NULL )
  237.         goto bail;
  238.     myGroupPosition = Q3Group_AddObject(myLightList, myAmbientLight);
  239.     if ( myGroupPosition == 0 )
  240.         goto bail;
  241.     myGroupPosition = Q3Group_AddObject(myLightList, myPointLight);
  242.     if ( myGroupPosition == 0 )
  243.         goto bail;
  244.     myGroupPosition = Q3Group_AddObject(myLightList, myFillLight);
  245.     if ( myGroupPosition == 0 )
  246.         goto bail;
  247.  
  248.     Q3Object_Dispose( myAmbientLight ) ;
  249.     Q3Object_Dispose( myPointLight ) ;
  250.     Q3Object_Dispose( myFillLight ) ;
  251.  
  252.     //    Done!
  253.     return ( myLightList );
  254.     
  255. bail:
  256.     //    If any of the above failed, then return nothing!
  257.     return ( NULL );
  258. }
  259.  
  260.  
  261.  
  262.  
  263. static void MyColorBoxFaces( TQ3BoxData *myBoxData )
  264. {
  265.     TQ3ColorRGB                faceColor ;
  266.     short                     face ;
  267.     
  268.     // sanity check - you need to have set up 
  269.     // the face attribute set for the box data 
  270.     // before calling this.
  271.     
  272.     if( myBoxData->faceAttributeSet == NULL )
  273.         return ;
  274.         
  275.     // make each face of a box a different color
  276.     
  277.     for( face = 0; face < 6; face++) {
  278.         
  279.         myBoxData->faceAttributeSet[face] = Q3AttributeSet_New();
  280.         switch( face ) {
  281.             case 0:
  282.                 faceColor.r = 1.0F;
  283.                 faceColor.g = 0.0F;
  284.                 faceColor.b = 0.0F;
  285.                 break;
  286.             
  287.             case 1:
  288.                 faceColor.r = 0.0F;
  289.                 faceColor.g = 1.0F;
  290.                 faceColor.b = 0.0F;
  291.                 break;
  292.             
  293.             case 2:
  294.                 faceColor.r = 0.0F;
  295.                 faceColor.g = 0.0F;
  296.                 faceColor.b = 1.0F;
  297.                 break;
  298.             
  299.             case 3:
  300.                 faceColor.r = 1.0F;
  301.                 faceColor.g = 1.0F;
  302.                 faceColor.b = 0.0F;
  303.                 break;
  304.             
  305.             case 4:
  306.                 faceColor.r = 1.0F;
  307.                 faceColor.g = 0.0F;
  308.                 faceColor.b = 1.0F;
  309.                 break;
  310.             
  311.             case 5:
  312.                 faceColor.r = 0.0F;
  313.                 faceColor.g = 1.0F;
  314.                 faceColor.b = 1.0F;
  315.                 break;
  316.         }
  317.         Q3AttributeSet_Add(myBoxData->faceAttributeSet[face], kQ3AttributeTypeDiffuseColor, &faceColor);
  318.     }
  319. }
  320.  
  321. static TQ3GroupPosition MyAddTransformedObjectToGroup( TQ3GroupObject theGroup, TQ3Object theObject, TQ3Vector3D *translation )
  322. {
  323.     TQ3TransformObject    transform;
  324.  
  325.     transform = Q3TranslateTransform_New(translation);
  326.     Q3Group_AddObject(theGroup, transform);    
  327.     Q3Object_Dispose(transform);
  328.     return Q3Group_AddObject(theGroup, theObject);    
  329. }
  330.  
  331.  
  332. TQ3GroupObject MyNewModel()
  333. {
  334.     TQ3GroupObject            myGroup = NULL;
  335.     TQ3GeometryObject        myBox;
  336.     TQ3BoxData                myBoxData;
  337.     TQ3ShaderObject            myIlluminationShader ;
  338.     
  339.     TQ3SetObject            faces[6] ;
  340.     short                    face ;
  341.             
  342.     // Create a group for the complete model.
  343.     // do not use Q3OrderedDisplayGroup_New since in this
  344.     // type of group all of the translations are applied before
  345.     // the objects in the group are drawn, in this instance we 
  346.     // dont want this.
  347.     if ((myGroup = Q3DisplayGroup_New()) != NULL ) 
  348.     {
  349.             
  350.         // Define a shading type for the group
  351.         // and add the shader to the group
  352.         myIlluminationShader = Q3PhongIllumination_New();
  353.         Q3Group_AddObject(myGroup, myIlluminationShader);
  354.  
  355.         // set up the colored faces for the box data
  356.         myBoxData.faceAttributeSet = faces;
  357.         myBoxData.boxAttributeSet = NULL;
  358.         MyColorBoxFaces( &myBoxData ) ;
  359.         
  360.         #define    kBoxSide        0.8F
  361.         #define    kBoxSidePlusGap    0.1F
  362.  
  363.         // create the box itself
  364.         Q3Point3D_Set(&myBoxData.origin, 0.0F, 0.0F, 0.0F);
  365.         Q3Vector3D_Set(&myBoxData.orientation, 0.0F, kBoxSide, 0.0F);
  366.         Q3Vector3D_Set(&myBoxData.majorAxis, 0.0F, 0.0F, kBoxSide);    
  367.         Q3Vector3D_Set(&myBoxData.minorAxis, kBoxSide, 0.0F, 0.0F);    
  368.         myBox = Q3Box_New(&myBoxData);
  369. #if 0    // one box
  370.         Q3Group_AddObject(myGroup, myBox);
  371. #else    // 4 boxes
  372.         {
  373.             TQ3Vector3D                translation;
  374.             translation.x =  0.0F;                
  375.             translation.y = kBoxSidePlusGap; 
  376.             translation.z =  0.0F;
  377.             MyAddTransformedObjectToGroup( myGroup, myBox, &translation ) ;
  378.             translation.x =  2 * kBoxSide;    
  379.             translation.y = kBoxSidePlusGap; 
  380.             translation.z =  0.0F;
  381.             MyAddTransformedObjectToGroup( myGroup, myBox, &translation ) ;
  382.             translation.x =  0.0F;                
  383.             translation.y = kBoxSidePlusGap; 
  384.             translation.z = -2 * kBoxSide;
  385.             MyAddTransformedObjectToGroup( myGroup, myBox, &translation ) ;
  386.             translation.x = -2 * kBoxSide;    
  387.             translation.y = kBoxSidePlusGap; 
  388.             translation.z =  0.0F;
  389.             MyAddTransformedObjectToGroup( myGroup, myBox, &translation ) ;
  390.         }
  391. #endif
  392.         for( face = 0; face < 6; face++) {
  393.             if( myBoxData.faceAttributeSet[face] != NULL )
  394.                 Q3Object_Dispose(myBoxData.faceAttributeSet[face]);
  395.         }
  396.         
  397.         if( myBox ) 
  398.             Q3Object_Dispose( myBox );
  399.     }
  400.     
  401.     // dispose of the objects we created here
  402.     if( myIlluminationShader ) 
  403.         Q3Object_Dispose(myIlluminationShader);    
  404.             
  405.     
  406.     //    Done!
  407.     return ( myGroup );
  408. }
  409.  
  410. void pvCamera_Fit(DocumentPtr theDocument)
  411. {    
  412.     TQ3Point3D         from, to;
  413.     TQ3BoundingBox    viewBBox;
  414.     float            fieldOfView, hither, yon;
  415.  
  416.     if (!theDocument)
  417.         return;
  418.  
  419.     if (!theDocument->fModel)
  420.         return;
  421.  
  422.     pvBBox_Get(theDocument, &viewBBox);
  423.     pvBBoxCenter(&viewBBox, &to);
  424.     
  425.  
  426.     {
  427.         TQ3Vector3D viewVector;
  428.         TQ3Vector3D    normViewVector;
  429.         TQ3Vector3D    eyeToFrontClip;
  430.         TQ3Vector3D    eyeToBackClip;
  431.          TQ3Vector3D    diagonalVector;
  432.         float        viewDistance;
  433.         float         maxDimension;
  434.  
  435.         Q3Point3D_Subtract(&viewBBox.max,
  436.                            &viewBBox.min,
  437.                            &diagonalVector);
  438.         maxDimension = Q3Vector3D_Length(&diagonalVector);
  439.         if (maxDimension == 0.0F)
  440.             maxDimension = 1.0F;
  441.  
  442.         maxDimension *= 8.0F / 7.0F;
  443.     
  444.         from.x = to.x;
  445.         from.y = to.y;
  446.         from.z = to.z + (2 * maxDimension);        
  447.  
  448.         Q3Point3D_Subtract(&to, &from, &viewVector);
  449.         viewDistance = Q3Vector3D_Length(&viewVector);
  450.         Q3Vector3D_Normalize(&viewVector, &normViewVector);
  451.         
  452.         maxDimension /= 2.0F;
  453.         
  454.         Q3Vector3D_Scale(&normViewVector, 
  455.                         viewDistance - maxDimension,
  456.                         &eyeToFrontClip);
  457.                         
  458.         Q3Vector3D_Scale(&normViewVector, 
  459.                         viewDistance + maxDimension,
  460.                         &eyeToBackClip);
  461.         
  462.         hither     = Q3Vector3D_Length(&eyeToFrontClip);
  463.         yon     = Q3Vector3D_Length(&eyeToBackClip);
  464.         
  465.         fieldOfView = Q3Math_RadiansToDegrees(1.25 * ErMath_Atan(maxDimension/hither));
  466.     }
  467.  
  468.     {
  469.         TQ3ViewAngleAspectCameraData     data;
  470.         TQ3Vector3D     up     = { 0.0F, 1.0F, 0.0F };
  471.  
  472.         data.cameraData.placement.cameraLocation     = from;
  473.         data.cameraData.placement.pointOfInterest     = to;
  474.         data.cameraData.placement.upVector             = up;
  475.     
  476.         data.cameraData.range.hither = hither;
  477.         data.cameraData.range.yon      = yon;
  478.     
  479.         data.cameraData.viewPort.origin.x = -1.0F;
  480.         data.cameraData.viewPort.origin.y =  1.0F;
  481.         data.cameraData.viewPort.width  = 2.0F;
  482.         data.cameraData.viewPort.height = 2.0F;
  483.  
  484.         data.fov = Q3Math_DegreesToRadians(fieldOfView);
  485.         
  486.         {
  487.             float w = (float)(theDocument->fWidth);
  488.             float h = (float)(theDocument->fHeight);
  489.  
  490.             data.aspectRatioXToY = w/h;
  491.         }
  492.         
  493.         if (theDocument->fView)
  494.         {
  495.             TQ3CameraObject camera;
  496.             
  497.             Q3View_GetCamera(theDocument->fView, &camera);
  498.             if (camera) {
  499.                 Q3ViewAngleAspectCamera_SetData(camera, &data);
  500.                 Q3Object_Dispose(camera);
  501.             }
  502.             else {
  503.                 camera  = Q3ViewAngleAspectCamera_New (&data);
  504.                 if (camera) {
  505.                     Q3View_SetCamera (theDocument->fView, camera);
  506.                     Q3Object_Dispose(camera);
  507.                 }
  508.             }
  509.         }
  510.     }
  511. }
  512.  
  513. void pvBBox_Get(DocumentPtr theDocument, TQ3BoundingBox *bbox)
  514. {            
  515.     if (theDocument->fView)
  516.     {
  517.         Q3View_StartBoundingBox(theDocument->fView, kQ3ComputeBoundsExact);
  518.         do
  519.         {
  520.             if (Q3DisplayGroup_Submit(theDocument->fModel, theDocument->fView) == kQ3Failure)
  521.             {
  522.                 Q3View_Cancel(theDocument->fView);
  523.                 return;
  524.             }
  525.         } while (Q3View_EndBoundingBox(theDocument->fView, bbox) == kQ3ViewStatusRetraverse);
  526.     }
  527.     else
  528.     {
  529.         Q3Point3D_Set(&(bbox->min), -0.1F, -0.1F, -0.1F);
  530.         Q3Point3D_Set(&(bbox->max), 0.1F, 0.1F, 0.1F);
  531.         bbox->isEmpty = kQ3False;
  532.     }
  533. }
  534.  
  535. void pvBBoxCenter(TQ3BoundingBox *bbox, TQ3Point3D *center)
  536. {
  537.      float    xSize, ySize, zSize;
  538.  
  539.     xSize = bbox->max.x - bbox->min.x;
  540.     ySize = bbox->max.y - bbox->min.y;
  541.     zSize = bbox->max.z - bbox->min.z;
  542.  
  543.     if (xSize <= kEPSILON &&
  544.         ySize <= kEPSILON &&
  545.         zSize <= kEPSILON)  {
  546.         bbox->max.x += 0.0001F;
  547.         bbox->max.y += 0.0001F;
  548.         bbox->max.z += 0.0001F;
  549.         
  550.         bbox->min.x -= 0.0001F;
  551.         bbox->min.y -= 0.0001F;
  552.         bbox->min.z -= 0.0001F;
  553.     }
  554.     
  555.     center->x = (bbox->min.x + bbox->max.x) / 2.0F;
  556.     center->y = (bbox->min.y + bbox->max.y) / 2.0F;
  557.     center->z = (bbox->min.z + bbox->max.z) / 2.0F;
  558. }
  559.